﻿using Infrastructure.Model;
using Infrastructure.MyException;
using Microsoft.AspNetCore.Http.HttpResults;
using ShareCode.Dto;
using ShareCode.Entity;
using ShareCode.Util.Extension;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Dao
{
    public class BaseTreeDao<T> : BaseContainTitleDao<T> where T : BaseTreeEntity, new()
    {
        public override Expressionable<T> GetSearchExpression(PagingDto pars)
        {
            var whereExpression = base.GetSearchExpression(pars)
          .AndIF(pars.SearchField.HasLong("TreeParentId"), t => t.TreeParentId == pars.SearchField.GetLong("TreeParentId"))
          .AndIF(pars.SearchField.HasLong("TreeRootId"), t => t.TreeRootId == pars.SearchField.GetLong("TreeRootId"))
          .AndIF(pars.SearchField.HasString("TheCode"), t => t.TheCode == pars.SearchField.GetString("TheCode"));

            return whereExpression;
        }

        public async override Task<bool> UpdateStateAsync(List<long> id, int state)
        {
            List<long> TempIds = id;

            var enity = await FirstAsync(t => id.Contains(t.Id));

            var lists = await Context.Queryable<T>().Where(t => t.TreeRootId == enity.TreeRootId).Select(t => new { t.Id, t.TreeParentId }).ToListAsync();

            void fun(List<long> ids)
            {
                var tempids = lists.FindAll(t => ids.Contains(t.TreeParentId) && t.TreeParentId != 0).Select(t => t.Id).ToList();

                if (tempids != default && tempids.Count > 0)
                {
                    TempIds.AddRange(tempids);
                    fun(TempIds);
                }
            };

            fun(id);

            return await UpdateAsync(t => t.State == state, t => TempIds.Contains(t.Id));
        }
        public async virtual Task<bool> DeleteByIdAsync(long id)
        {

            var model = await GetByIdAsync(id);
            if (model == default) throw new ShowUserLogicException("没有找到指定数据");


            List<long> TempIds = new() { id };

            var lists = await Context.Queryable<T>().Where(t => t.TreeRootId == model.TreeRootId).Select(t => new { t.Id, t.TreeParentId }).ToListAsync();

            void fun(List<long> ids)
            {
                var tempids = lists.FindAll(t => ids.Contains(t.TreeParentId) && t.TreeParentId != 0).Select(t => t.Id).ToList();

                if (tempids != default && tempids.Count > 0)
                {
                    TempIds.AddRange(tempids);
                    fun(TempIds);
                }
            };

            fun(TempIds);

            //await this.UpdateAsync(t => t.TreeNodeSonsAmount == t.TreeNodeSonsAmount - 1, t => t.Id == model.Id);

            return await Context.Deleteable<T>().Where(t => TempIds.Contains(t.TreeParentId)).ExecuteCommandAsync() > 0;
        }

        public async override Task<bool> LogicDeleteByIdAsync(List<long> id)
        {
            List<long> TempIds = id;

            var enity = await FirstAsync(t => id.Contains(t.Id));

            var lists = await Context.Queryable<T>().Where(t => t.TreeRootId == enity.TreeRootId).Select(t => new { t.Id, t.TreeParentId }).ToListAsync();

            void fun(List<long> ids)
            {
                var tempids = lists.FindAll(t => ids.Contains(t.TreeParentId) && t.TreeParentId != 0).Select(t => t.Id).ToList();

                if (tempids != default && tempids.Count > 0)
                {
                    TempIds.AddRange(tempids);
                    fun(TempIds);
                }
            };

            fun(id);

            return await UpdateAsync(t => t.IsDelete == 1, t => TempIds.Contains(t.Id));
        }

        public async override Task<bool> UnLogicDeleteByIdAsync(List<long> ids)
        {
            List<long> TempIds = ids;

            var enity = await FirstAsync(t => ids.Contains(t.Id));

            var lists = await Context.Queryable<T>().Where(t => t.TreeRootId == enity.TreeRootId).Select(t => new { t.Id, t.TreeParentId }).ToListAsync();

            void fun(List<long> ids)
            {
                var tempids = lists.FindAll(t => ids.Contains(t.TreeParentId) && t.TreeParentId != 0).Select(t => t.Id).ToList();

                if (tempids != default && tempids.Count > 0)
                {
                    TempIds.AddRange(tempids);
                    fun(TempIds);
                }
            };

            fun(ids);

            return await UpdateAsync(t => t.IsDelete == 0, t => TempIds.Contains(t.Id));
        }
        public async virtual Task<T?> GetTreeRootAsync(long id)
        {
            var Entity = await this.GetByIdAsync(id);
            if (Entity == default)
            {
                return default;
            }

            if (Entity.TreeParentId == 0)
            {
                return Entity;
            }

            Entity = await GetFirstAsync(t => t.Id == Entity.TreeRootId);

            return Entity;
        }

        public async virtual Task<List<long>> GetTreeRootsAsync(long id)
        {
            List<long> ids = new List<long>();
            var Entity = await this.GetByIdAsync(id);

            if (Entity == default)
            {
                return new List<long>();
            }

            var TempIds = await Context.Queryable<T>().Where(t => t.TreeRootId == Entity.TreeRootId).Select(t => t.Id).ToListAsync();

            return TempIds;

        }

        public async virtual Task<List<long>> GetTreeParentIds(long id)
        {
            List<long> ids = new List<long>();
            var Entity = await this.GetByIdAsync(id);

            if (Entity == default)
            {
                return new List<long>();
            }

            ids.Add(id);

            var lists = await Context.Queryable<T>().Where(t => t.TreeRootId == Entity.TreeRootId).Select(t => new { t.Id, t.TreeParentId }).ToListAsync();
            var parentId = Entity.TreeParentId;
            while (true)
            {
                var tempM = lists.FirstOrDefault(t => t.Id == parentId);

                if (tempM == default)
                {
                    break;
                }

                parentId = tempM.TreeParentId;

                ids.Add(tempM.Id);
            }

            return ids;
        }

        public async virtual Task<bool> TreeInsertSon(T entity)
        {
            long pid = entity.TreeParentId;
            if (pid != 0)
            {
                var brother = await this.FirstAsync(t => t.TreeParentId == pid, t => t.Sort, OrderByType.Desc);

                if (brother == default)
                {
                    var pModel = this.GetById(pid);

                    if (pModel == default)
                    {
                        throw new ShowUserLogicException($"{pid},没有找到数据");
                    }

                    entity.TreeParentId = pid;
                    entity.TreeRootId = pModel.TreeRootId;

                    var re = this.Insert(entity);
                    if (re)
                    {
                        return true;
                    }
                    else
                    {
                        throw new ShowUserLogicException("数据入库失败");
                    }
                }
                else
                {
                    return await TreeInsertAfter(entity, brother.Id);
                }
            }

            try
            {
                this.Context.Ado.BeginTran();

                var re = this.Insert(entity);

                this.Context.Tracking(entity);

                entity.TreeParentId = 0;
                entity.TreeRootId = entity.Id;

                this.Update(entity);

                this.Context.Ado.CommitTran();

                this.Context.ClearTracking();
                return true;
            }
            catch (Exception ex)
            {
                this.Context.Ado.RollbackTran();
                throw new ShowUserLogicException(ex.Message);
            }

        }

        public async virtual Task<bool> TreeInsertBefore(T entity, long brotherId)
        {
            var brotherModel = this.GetById(brotherId);

            if (brotherModel == default)
            {
                throw new ShowUserLogicException($"{brotherModel},没有找到数据");
            }

            try
            {
                this.Context.Ado.BeginTran();

                var aa = await this.Context.Updateable<T>().SetColumns(t => t.Sort == t.Sort + 1)
                     .Where(t => t.TreeParentId == brotherModel.TreeParentId && t.Sort >= brotherModel.Sort)
                     .ExecuteCommandAsync() > 0;

                if (!aa)
                {
                    throw new Exception("更新数据失败");
                }

                entity.TreeParentId = brotherModel.TreeParentId;
                entity.TreeRootId = brotherModel.TreeRootId;
                entity.Sort = brotherModel.Sort;

                if (this.Insert(entity))
                {
                    this.Context.Ado.CommitTran();
                    return true;
                }

                throw new Exception("写入数据失败");


            }
            catch (Exception ex)
            {
                this.Context.Ado.RollbackTran();
                throw new ShowUserLogicException(ex.Message);
            }

        }

        public async virtual Task<bool> TreeInsertAfter(T entity, long brotherId)
        {
            var brotherModel = this.GetById(brotherId);

            if (brotherModel == default)
            {
                throw new ShowUserLogicException($"{brotherModel},没有找到数据");
            }

            try
            {
                this.Context.Ado.BeginTran();

                var aa = await this.Context.Updateable<T>().SetColumns(t => t.Sort == t.Sort + 1)
                     .Where(t => t.TreeParentId == brotherModel.TreeParentId && t.Sort > brotherModel.Sort)
                     .ExecuteCommandAsync() > 0;

                if (!aa)
                {
                    throw new Exception("更新数据失败");
                }

                entity.TreeParentId = brotherModel.TreeParentId;
                entity.TreeRootId = brotherModel.TreeRootId;
                entity.Sort = brotherModel.Sort + 1;

                if (this.Insert(entity))
                {
                    this.Context.Ado.CommitTran();
                    return true;
                }

                throw new Exception("写入数据失败");


            }
            catch (Exception ex)
            {
                this.Context.Ado.RollbackTran();
                throw new ShowUserLogicException(ex.Message);
            }

        }



        public override async  Task<PagingWithDataModel<T>> ListPageAsync(PagingDto? pars)
        {
            pars ??= new PagingDto();
            pars.IsDesc = null;

            var myreturn = new PagingWithDataModel<T>(pars);//自动提取分页参数

            Expression<Func<T, bool>> whereExpression = GetSearchExpression(pars).ToExpression();

            if (pars.TotalRows < 1)
            {
                var page = this.TranslatePageModel(myreturn);
                var list = await this.GetPageListAsync(whereExpression, page, t => t.Sort, SqlSugar.OrderByType.Asc);
                myreturn.List = list;
                myreturn.TotalRows = page.TotalCount;
            }
            else
            {
                var list = await Context.Queryable<T>().OrderBy(t => t.Sort).Where(whereExpression).Take(pars.PageSize).ToListAsync();
                myreturn.List = list;
            }


            return myreturn;
        }

        public override async  Task<List<T>> ListAsync(PagingDto? pars)
        {
            pars ??= new PagingDto();
            pars.IsDesc = null;

            Expression<Func<T, bool>> whereExpression = GetSearchExpression(pars).ToExpression();

            return await GetListAsync(whereExpression, t => t.Sort, SqlSugar.OrderByType.Asc);
        }
    }
}
